(function(){
var	rbracket = /\[\]$/,
	rCRLF = /\r?\n/g,
	// jquery-1.7.2.js
    rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
    rselectTextarea = /^(?:select|textarea)/i;
    //jquery-3.1.1
    rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
	rsubmittable = /^(?:input|select|textarea|keygen)/i,
    rcheckableType = ( /^(?:checkbox|radio)$/i );
	$.fn.extend({
		"serializable"  : function (separator) { //see jquery-3.1.1.js
            var elements =  this.elements();
            function serializable(elements) {
                var json = {};
                $.makeArray(elements).forEach(function(item ){
                    var _this = $( item );
                    var val = _this.val();
                    val = val === ""  || val === "undefined" ? null : val;
                    var name = item.name;
                    if(rcheckableType.test(item.type)){
                        if(item.checked){
                            //元素为radio 或者 没有该checkbox同名的checkbox不使用数组
                            if(!_this.is(":radio") || elements.filter(function (e,i) { return e.name == item.name }).length <= 1){
                                json[name] = val;
                            }else {//多个同名的checkbox使用数组
                                json[name] = [val];
                            }
                        }
                    }else if(json.hasOwnProperty(name)){
                         if(separator){
                             json[name] = json[name]+( val ? separator + val : "");
                         }else{
                             if(json[name]  instanceof Array){
                                 json[name].push(val);
                             }else{
                                 json[name] = [json[name],val];
                             }
                         }
                   }else {
                        json[name] = val;
                    }
                });
                return json;
            }

            if(this.length < 1 || !this[0]){
               return ;
            }
            if(this[0].tagName == 'FORM'){
               return serializable(elements);
            }else if(this[0].tagName == 'TABLE'){
                return elements.map(function (item,index,array) {
                    return serializable(item);
                });
            }else {
                return serializable(elements);
            }
        },
        "elements" : function () {
			var elements;
			if(this.length < 1 || !this[0]){
			    return [];
            }
            if(this.tagName == 'FORM' || this[0].tagName == 'FORM'){
                elements = this.map(function(){
                           var elements = jQuery.prop( this, "elements" );
                          return elements ? jQuery.makeArray( elements ) : this;
                      });
            }else if(this.tagName == 'table' || this[0].tagName == 'TABLE') {
                var rows = $.makeArray($(this).find("tbody tr"));
                elements = rows.map(function (item,index,array) {
                      var fields  = $(item).find(":input").filter(function(item,index){
                             return this.name && !this.disabled && (rcheckableType.test(this.type) || rselectTextarea.test( this.nodeName ) || rinput.test( this.type ) );
                         });
                      return $.makeArray(fields);
                });
                elements = elements ? jQuery.makeArray( elements ) : this;
			}else {
                elements = $(this).find(":input");
            }
           return elements.filter(function(item,index){ //see jquery-3.1.1.js
                if(Array.isArray(item)){
                    return item && item.length > 0;
                }else {
                    return this.name && !this.disabled && ( rcheckableType.test(this.type) || rselectTextarea.test( this.nodeName ) || rinput.test( this.type ) );
                }
            });
        },
        /**
		 *
         * @param jsonData json对象
         * @param option {}  参数设置对象 | function callback 方法
         * @returns {Mixed|jQuery|HTMLElement}
         */
        'deserializable':function(jsonData,option){
            // 获取表单元素
            var elements = this.elements();
            var setting = {};
            if(Object.prototype.toString.call(option) === '[object Object]'){
				  setting = $.extend(setting,{
                        multiple:'string',
						separator:',',
						prefix:'',
						suffix:'',
						callback:null,
						reset:true
					},option);
			}
            // 是否清空表单，默认自动清空
            if (setting['reset']){
                $(this)[0].reset();
            }
            // 传入的json数据空、有误
			if(!jsonData || $.type(jsonData) != 'object' || $.isEmptyObject(jsonData)){
				return;
			}
			// 遍历容器内所有表单元素
            elements.each(function(){
            	var _this = $(this);
				var name = _this.attr("name");
				if(!jsonData.hasOwnProperty(name)){
					return;
				}
				if (_this.is(":radio")) {// 当表单元素为 radio 时
                    elements.filter(":radio[name='"+name+"']").prop("checked",false);// 取消 radio 选中状态
                    elements.filter(":radio[name='"+name+"'][value="+jsonData[name]+"]").prop("checked",true);// 选中 radio
				} else if (_this.is(":checkbox")){// 当表单元素为 checkbox 时
					// 取消 checkbox 选中状态
                    elements.filter(":checkbox[name='"+name+"']").prop("checked",false);
					var checkBoxData = jsonData[name];
					if ($.type(checkBoxData) == 'array'){
						$.each(checkBoxData, function(i, val){
                            elements.filter(":checkbox[name='"+name+"'][value="+val+"]").prop("checked",true);
						});
					}else if($.type(checkBoxData) == 'string'){
						$.each(checkBoxData.split(setting.separator), function(i, val){
                            elements.filter(":checkbox[name='"+name+"'][value="+val+"]").prop("checked",true);
						});
					}
					else {
                        elements.filter(":checkbox[name='"+name+"'][value="+checkBoxData+"]").prop("checked",true);
					}
				}else if(_this.is("select") && _this.find("option").length < 1){//下拉框无选项
				    if(Array.isArray(jsonData[name])){
                        var options = [];
				        for(var i = 0 ; i < jsonData[name].length ; i++){
                            options.push("<option value='"+jsonData[name][i]+"'>"+jsonData[name][i]+"</option>");
                        }
                        _this.append(options.join(""));
                    }else {
                        _this.append("<option value='"+jsonData[name]+"'>"+jsonData[name]+"</option>");
                    }
                    _this.val(jsonData[name]);
                }else {
                    _this.val(jsonData[name]);
				}
			});
			if(typeof option == 'function'){
                option(jsonData);
			}else if(setting && typeof  setting.callback == 'function'){
                setting.callback(jsonData);
			}
            return $(this);
        }
	});
	
})(jQuery);